package org.linlinjava.litemall.wx.service;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.linlinjava.litemall.core.payment.PaymentResponseCode;
import org.linlinjava.litemall.core.payment.paypal.service.impl.UserPaypalServiceImpl;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.db.beans.Constants;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.wx.dto.UserRechargeDTO;
import org.linlinjava.litemall.wx.dto.WxResetPaymentCodeByCodeDTO;
import org.linlinjava.litemall.wx.dto.WxRewardConfigDTO;
import org.linlinjava.litemall.wx.dto.WxRewardDTO;
import org.linlinjava.litemall.wx.util.WxResponseEnum;
import org.linlinjava.litemall.wx.vo.LitemallRechargeConsumptionVo;
import org.linlinjava.litemall.wx.vo.WxRewardLogVo;
import org.linlinjava.litemall.wx.vo.WxRewardRuleVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import static org.linlinjava.litemall.db.beans.Constants.*;
import static org.linlinjava.litemall.wx.util.WxResponseCode.AUTH_CAPTCHA_UNMATCH;

/**
 * @author ：stephen
 * @date ：Created in 2020/4/9 17:15
 * @description：TODO
 */
@Service
public class WxUserService {
    private static final Log log = LogFactory.getLog(WxUserService.class);

    @Autowired
    private LitemallUserRechargeOrderService litemallUserRechargeOrderService;
    @Autowired
    private UserPaypalServiceImpl userPaypalService;
    @Autowired
    private LitemallUserService litemallUserService;
    @Autowired
    private LitemallRechargeConsumptionService litemallRechargeConsumptionService;
    @Autowired
    private LitemallRechargeTransactionsService litemallRechargeTransactionsService;
    @Autowired
    private LitemallOrderGoodsService litemallOrderGoodsService;
    @Autowired
    private LumiereSubscribeService lumiereSubscribeService;

    @Autowired
    private LitemallIntegralLogService integralLogService;

    /**
     * litemall奖励规则服务
     */
    @Autowired
    private LitemallRewardRuleService litemallRewardRuleService;

    /**
     * litemall奖励规则配置服务
     */
    @Autowired
    private LitemallRewardRuleConfigService litemallRewardRuleConfigService;

    /**
     * 管理服务
     */
    @Autowired
    private LitemallAdminService adminService;

    /**
     * 用户服务
     */
    @Autowired
    private LitemallUserService userService;

    @Autowired
    private LitemallPayCodeSerivce litemallPayCodeSerivce;

    /**
     * litemall分布细节服务
     */
    @Autowired
    private LitemallDistributionDetailService litemallDistributionDetailService;

    /**
     * 分配日志服务
     */
    @Autowired
    private DistributionLogService distributionLogService;

    @Autowired
    private LumiereCouponStrategyService lumiereCouponStrategyService;

    @Autowired
    private LumiereCouponService lumiereCouponService;

    /**
     * APP奖励规则显示
     *
     * @param page        页面
     * @param limit       限制
     * @return {@link Object}
     */
    public Object log(Integer page,Integer limit,Integer userId) {
        if(userId==null){
            ResponseUtil.unlogin();
        }
        if(page != null && limit != null){
            //PageHelper.startPage(page, limit);
        }
        /**奖励显示*/
        //获得邀请人的所有邀请记录
        List<LitemallDistributionLog> logs = distributionLogService.findByUserId(userId);
        List<WxRewardLogVo> vos = new ArrayList<>();
        logs.stream().forEach(log -> {
            //组装结果集
            WxRewardLogVo vo = new WxRewardLogVo();
            if (log.getUserId() != null) {
                LitemallUser user = userService.findById(log.getUserId());

                if(user != null){
                    vo.setEmail(user.getEmail());
                    vo.setUserName(user.getUsername());
                }
            }
            vo.setId(log.getId());
            vo.setType(log.getType());
            vo.setInviteNum(log.getInviteNum());
            DateTimeFormatter timeDtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            vo.setRegisteDate(log.getInviteDate().format(timeDtf));
            Integer rewardNum = 0;

            List<LitemallDistributionDetail> rewardDetailList =  litemallDistributionDetailService.countByLogId(log.getId());
            if(rewardDetailList.size() > 0){
                for(LitemallDistributionDetail distributionDetail : rewardDetailList){
                    rewardNum +=distributionDetail.getPresentCouponId().length;
                    if(distributionDetail.getPresentPoints() != null && distributionDetail.getPresentPoints().compareTo(new BigDecimal(0)) >0){
                        rewardNum ++;
                    }
                }
            }
            vo.setRewardNum(rewardNum);
            vos.add(vo);
        });
        /**规则列表*/

        return ResponseUtil.okList(vos,logs);
    }



    /**
     * 规则列表
     *
     * @param isExpired 是过期
     * @param page      页面
     * @param limit     限制
     * @param sort      排序
     * @param order     订单
     * @param ruleName  规则名称
     * @param status    状态
     * @return {@link Object}
     */
    public Object listRule(Byte isExpired, Integer page,
                           Integer limit, String sort, String order, String ruleName, Byte status) {
        List<LitemallRewardRule> list = litemallRewardRuleService.list(ruleName, status,null,false);
        //奖励规则列表
        List<WxRewardRuleVo> vos = new ArrayList<>();
        List<WxRewardRuleVo> finalVos = vos;
        if (isExpired != null) {
            list = list.stream().sorted(Comparator.comparing(LitemallRewardRule::getStatus)).collect(Collectors.toList());

            vos = list.stream().map(rule -> {
                WxRewardRuleVo vo = new WxRewardRuleVo();
                BeanUtils.copyProperties(rule, vo);
                if (rule.getAddAdminId() != null) {
                    LitemallAdmin adminUser = adminService.findById(rule.getAddAdminId());
                    if (adminUser != null) {
                        vo.setAddAdminName(adminUser.getUsername());
                    }
                }
                return vo;
            }).collect(Collectors.toList());
        } else {
            list = list.stream().sorted(Comparator.comparing(
                    LitemallRewardRule::getStatus).reversed()).collect(Collectors.toList());

            list.stream().forEach(rule -> {
                WxRewardRuleVo vo = new WxRewardRuleVo();
                if (rule.getEndDate() != null) {
                    if (rule.getEndDate().isAfter(LocalDate.now())) {
                        vo.setIsExpired((byte) 3);
                    } else {
                        vo.setIsExpired((byte) 2);
                    }
                } else {
                    if (rule.getStartDate() != null) {
                        if (rule.getStartDate().isAfter(LocalDate.now())) {
                            vo.setIsExpired((byte) 2);
                        } else {
                            vo.setIsExpired((byte) 3);
                        }
                    } else {
                        vo.setIsExpired((byte) 3);
                    }
                }
                BeanUtils.copyProperties(rule, vo);

                if (rule.getAddAdminId() != null) {
                    LitemallAdmin adminUser = adminService.findById(rule.getAddAdminId());
                    if (adminUser != null) {
                        vo.setAddAdminName(adminUser.getUsername());
                    }
                }

                if (isExpired != null) {
                    if (vo.getIsExpired() == isExpired) {
                        finalVos.add(vo);
                    }
                } else {
                    finalVos.add(vo);
                }
            });
        }

        //规则配置信息
        vos.stream().forEach(vo->{
            Integer ruleId = vo.getId();
            WxRewardDTO dto = new WxRewardDTO();
            LitemallRewardRule rule = litemallRewardRuleService.findById(ruleId);
            BeanUtils.copyProperties(rule, dto);

            DateTimeFormatter timeDtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            dto.setStartDate(rule.getStartDate().format(timeDtf));
            dto.setEndDate(rule.getEndDate().format(timeDtf));
            //规则配置
            List<LitemallRewardRuleConfig> configList = litemallRewardRuleConfigService.listByRuleId(ruleId);
            List<WxRewardConfigDTO> configDtos = configList.stream().map(config -> {
                WxRewardConfigDTO configDto = new WxRewardConfigDTO();
                BeanUtils.copyProperties(config, configDto);

                Long[] couponArray = config.getPresentCouponId();
                List<LumiereCouponStrategy> coupons = new ArrayList<>();
                String couponName = "";
                if(couponArray != null && couponArray.length > 0){
                    for (int i = 0; i < couponArray.length; i++) {
                        LumiereCouponStrategy couponStrategy = lumiereCouponStrategyService.findByid(couponArray[i].longValue());
                        LumiereCoupon coupon = lumiereCouponService.getById(couponStrategy.getCouponId());
                        couponStrategy.setCouponName(coupon.getName());
                        couponName += coupon.getName();
                        coupons.add(couponStrategy);
                    }
                }

                configDto.setPresentCouponId(coupons);
                configDto.setCouponName(couponName);

                return configDto;
            }).collect(Collectors.toList());
            dto.setAdminRewardConfigDtos(configDtos);
            vo.setWxRewardDto(dto);
        });

        return ResponseUtil.okList(vos);
    }


    /**
     * 用户充值
     * @param userId
     * @param dto
     * @return
     */
    public Object recharge(Integer userId, UserRechargeDTO dto) {

        LitemallUserRechargeOrder order = new LitemallUserRechargeOrder();
        order.setAmount(dto.getAmount());
        order.setUserId(userId);
        litemallUserRechargeOrderService.add(order);
        return order;
    }

    /**
     * 充值支付
     * @param id
     * @param userId
     * @param successUrl
     * @param cancelUrl
     * @return
     */
    public Object getPayment(Integer id, Integer userId, String successUrl, String cancelUrl) {
        return userPaypalService.getPayment(userId, id, successUrl, cancelUrl,"");
    }

    /**
     * 支付成功
     * @param paymentId
     * @param payerId
     * @return
     */
    @Transactional
    public Object executePayment(String paymentId, String payerId) {
        try {
            Object payment = userPaypalService.executePayment(paymentId, payerId);
            createOrUpdateAmount(paymentId);
            return payment;
        }catch (Exception e){
            return ResponseUtil.fail(PaymentResponseCode.PAYMENT_FAIL, "支付失败");
        }
    }

    /**
     * 更新余额
     * @param paymentId
     */
    @Transactional
    public synchronized Object createOrUpdateAmount(String paymentId) {
        log.info("更新余额开始===》");
        LitemallUserRechargeOrder order = litemallUserRechargeOrderService.findByOutTradeNo(paymentId);
        if(order.getPayStatus() != Constants.PAY_STATUS_DONE){
            return ResponseUtil.fail(WxResponseEnum.NOT_FIND_ORDER);
        }
        LitemallUser user = litemallUserService.findById(order.getUserId());
        if(user == null){
            return ResponseUtil.fail(WxResponseEnum.NOT_FIND_USER);
        }
        //记录用户充值日志
        addRechargeConsumption(user, Constants.USER_SAVING, order.getAmount(),order.getId());

        //充值记录
        litemallRechargeTransactionsService.save(new LitemallRechargeTransactions()
                .setUserId(user.getId())
                .setUsername(user.getUsername())
                .setRechargeType(Constants.RECHARGE_TYPE_BALANCE)
                .setPayType(Constants.PAY_TYPE_PAYPAL)
                .setRechargeAmount(order.getAmount())
                .setRechargeSource(Constants.ORDER_SOURCE_APP)
        );

        LitemallUser update = new LitemallUser();
        update.setId(order.getUserId());

        update.setAvailableAmount(user.getAvailableAmount().add(order.getAmount()));
        //更新用户余额
        log.info("更新余额");
        if(!litemallUserService.updateById(update)){
            //更新失败，重新更新
            createOrUpdateAmount(paymentId);
        }
        log.info("更新余额结束===》");
        return null;
    }

    public Object bill(Integer userId, Integer page, Integer limit, String sort, String order) {
        List<LitemallRechargeConsumption> litemallRechargeConsumptions = litemallRechargeConsumptionService.querySelectiveList(userId, null, null, page, limit, sort, order);

        List<LitemallRechargeConsumptionVo> vos = new ArrayList<>();
        litemallRechargeConsumptions.stream().forEach(consumption -> {
            LitemallRechargeConsumptionVo vo = new LitemallRechargeConsumptionVo();
            BeanUtils.copyProperties(consumption, vo);
            vo.setPoints(0);
            String concerning = null;
            if (consumption.getType() == LOG_GIFTCARD_CONSUME) {
                if (consumption.getOrderId() != null) {
                    List<LitemallOrderGoods> orderGoods = litemallOrderGoodsService.queryByOid(consumption.getOrderId());
                    for (int i = 0; i < orderGoods.size(); i++) {
                        concerning = orderGoods.get(i).getGoodsName() ;

                        if(i != orderGoods.size() - 1){
                            concerning += ",";
                        }
                    }
                }
                vo.setConcerning(concerning);
                LitemallIntegralLog log = integralLogService.queryByConsumptionIdOrOrderId(consumption.getId(), null);
                if (log != null) {
                    vo.setPoints(log.getChangePoints().intValue());
                }
            } else{
                 if (consumption.getType() == LOG_GIFTCARD_SUBSCRIBE_CONSUME) {  //消费对象是订阅
                    if (consumption.getOrderId() != null) {
                        LumiereSubscribe subscribe = lumiereSubscribeService.findById(consumption.getOrderId());
                        if (subscribe != null) {
                            concerning = "订阅了--" + subscribe.getName();
                        }
                    }
                } else if (consumption.getType() == LOG_GIFTCARD_SUBSCRIBE_RENEVAL) {  //消费对象是订阅
                    if (consumption.getOrderId() != null) {
                        LumiereSubscribe subscribe = lumiereSubscribeService.findById(consumption.getOrderId());
                        if (subscribe != null) {
                            concerning = "续订了--" + subscribe.getName();
                        }
                    }
                } else if (consumption.getType() == LOG_GIFTCARD_SUBSCRIBE_GIVE) {  //消费对象是订阅
                    if (consumption.getOrderId() != null) {
                        LumiereSubscribe subscribe = lumiereSubscribeService.findById(consumption.getOrderId());
                        if (subscribe != null) {
                            concerning = "赠送了--" + subscribe.getName();
                        }
                    }
                }
                vo.setOrderId(0);
            }
            vo.setConcerning(StrUtil.isBlank(concerning)?"":concerning);
            vos.add(vo);
        });

        return ResponseUtil.okList(vos,litemallRechargeConsumptions);
    }

    public void addRechargeConsumption(LitemallUser user, Byte type, BigDecimal amount){
        addRechargeConsumption(user,type,amount,null);

    }

    public void addRechargeConsumption(LitemallUser user, Byte type, BigDecimal amount, Integer orderId){
        LitemallRechargeConsumption record = new LitemallRechargeConsumption();
        BeanUtils.copyProperties(user, record);
        record.setUserId(user.getId());
        record.setUsername(user.getUsername());
        record.setAddUserId(user.getId());
        record.setType(type);
        record.setAmount(amount);
        record.setOrderId(orderId);
        record.setOrderSource(Constants.ORDER_SOURCE_APP);
        if(record.getAvailableAmount() != null && Constants.USER_SAVING == type){
            record.setAvailableAmount(record.getAvailableAmount().add(amount));
        }else if(record.getAvailableAmount() != null && Constants.USER_CONSUME == type){
            record.setAvailableAmount(record.getAvailableAmount().subtract(amount));
        }
        log.info("插入充值记录");
        litemallRechargeConsumptionService.add(record);
    }

    public Object paymentCode(Integer userId, Integer payCode) {
        LitemallUser litemallUser = userService.findById(userId);
        if(ObjectUtil.isNull(litemallUser)){
            return ResponseUtil.badArgument();
        }
        litemallPayCodeSerivce.remove(Wrappers.lambdaQuery(LitemallPayCode.class)
                .eq(LitemallPayCode::getUserId,userId));
        LitemallPayCode litemallPayCode = LitemallPayCode.builder()
                .userId(userId)
                .paymentCode(payCode)
                .build();
        boolean save = litemallPayCodeSerivce.save(litemallPayCode);
        return ResponseUtil.ok(save);
    }

    public Object resetPaymentCode(Integer userId, Integer oldPayCode, Integer newPayCode) {
        LitemallUser litemallUser = userService.findById(userId);
        if(ObjectUtil.isNull(litemallUser)){
            return ResponseUtil.badArgument();
        }
        LitemallPayCode payCode = litemallPayCodeSerivce.getOne(Wrappers.lambdaQuery(LitemallPayCode.class)
                .eq(LitemallPayCode::getUserId,userId));
        if(!payCode.getPaymentCode().equals(oldPayCode)){
            return ResponseUtil.fail(203,"支付密码错误");
        }
        payCode.setPaymentCode(newPayCode);
        return litemallPayCodeSerivce.updateById(payCode)?ResponseUtil.ok():ResponseUtil.fail();
    }

    public Object resetPaymentCodeByCode(Integer userId, WxResetPaymentCodeByCodeDTO resetPaymentCodeByCodeDTO) {
        LitemallUser litemallUser = userService.findById(userId);
        if(ObjectUtil.isNull(litemallUser)){
            return ResponseUtil.badArgument();
        }
        String cacheCode = CaptchaCodeManager.getCachedCaptcha(resetPaymentCodeByCodeDTO.getMode()+"2");
        if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(resetPaymentCodeByCodeDTO.getCode()))
            return ResponseUtil.fail(AUTH_CAPTCHA_UNMATCH, "验证码错误");
        return ResponseUtil.ok();
    }

    public Object verify(Integer userId, Integer payCode) {
        LitemallUser litemallUser = userService.findById(userId);
        if(ObjectUtil.isNull(litemallUser)){
            return ResponseUtil.badArgument();
        }
        LitemallPayCode litemallPayCode = litemallPayCodeSerivce.getOne(Wrappers.lambdaQuery(LitemallPayCode.class)
                .eq(LitemallPayCode::getUserId,userId)
                .eq(LitemallPayCode::getPaymentCode,payCode));
        return ObjectUtil.isNotNull(litemallPayCode)?ResponseUtil.ok():ResponseUtil.fail(203,"支付密码错误");
    }

    public Object removePay(Integer userId) {
        boolean remove = litemallPayCodeSerivce.remove(Wrappers.lambdaQuery(LitemallPayCode.class).eq(LitemallPayCode::getUserId, userId));
        return ResponseUtil.ok(remove);
    }
}
